package com.ebraga.trackerclub.android.manager.core;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;

import com.ebraga.trackerclub.android.dao.api.ParameterDao;
import com.ebraga.trackerclub.android.dao.api.PositionDao;
import com.ebraga.trackerclub.android.dao.api.RankingDao;
import com.ebraga.trackerclub.android.dao.api.SyncDataDao;
import com.ebraga.trackerclub.android.dao.api.UserDao;
import com.ebraga.trackerclub.android.dao.api.webservice.ParameterWSDao;
import com.ebraga.trackerclub.android.dao.api.webservice.PositionWSDao;
import com.ebraga.trackerclub.android.dao.api.webservice.RankingWSDao;
import com.ebraga.trackerclub.android.dao.api.webservice.UserWSDao;
import com.ebraga.trackerclub.android.dao.entity.ParameterAndroid;
import com.ebraga.trackerclub.android.dao.entity.PositionAndroid;
import com.ebraga.trackerclub.android.dao.entity.RankingAndroid;
import com.ebraga.trackerclub.android.dao.entity.SyncDataAndroid;
import com.ebraga.trackerclub.android.dao.entity.UserAndroid;
import com.ebraga.trackerclub.android.exception.BackofficeDBConnectionException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeConnectionWebServicesException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeDaoException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeInvalidSessionDaoException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeInvalidURLWebServicesException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeWebServicesException;
import com.ebraga.trackerclub.android.exception.manager.BackofficeInvalidSessionManagerException;
import com.ebraga.trackerclub.android.exception.manager.BackofficeManagerException;
import com.ebraga.trackerclub.android.manager.api.SyncDataManager;
import com.ebraga.trackerclub.android.util.DLog;
import com.ebraga.trackerclub.android.util.enumeration.AndroidConfigurationParameterName;
import com.ebraga.trackerclub.rest.dao.entity.webservice.PositionWSEntity;
import com.ebraga.trackerclub.rest.dao.entity.webservice.UserWSEntity;

public abstract class SyncDataManagerImpl implements SyncDataManager {

	private final Logger logger = Logger.getLogger(SyncDataManagerImpl.class);
	
	private ParameterDao parameterDao;
	private ParameterWSDao parameterWSDAO;
	private RankingDao rankingDao;
	private RankingWSDao rankingWSDAO;
	private PositionDao positionDao;
	private PositionWSDao positionWSDAO;
	private UserWSDao userWSDAO;
	private SyncDataDao syncDataDao;
	private UserDao userDao;
	
	public void setParameterDao(ParameterDao parameterDao) {
		this.parameterDao = parameterDao;
	}
	
	public void setPositionDao(PositionDao positionDao) {
		this.positionDao = positionDao;
	}

	public void setParameterWSDAO(ParameterWSDao parameterWSDAO) {
		this.parameterWSDAO = parameterWSDAO;
	}
	
	
	public void setRankingDao(RankingDao rankingDao) {
		this.rankingDao = rankingDao;
	}	
	public void setRankingWSDAO(RankingWSDao rankingWSDAO) {
		this.rankingWSDAO = rankingWSDAO;
	}

	public void setPositionWSDAO(PositionWSDao positionWSDAO) {
		this.positionWSDAO = positionWSDAO;
	}
	
	public void setUserWSDAO(UserWSDao userWSDAO) {
		this.userWSDAO = userWSDAO;
	}	

	public void setSyncDataDao(SyncDataDao syncDataDao) {
		this.syncDataDao = syncDataDao;
	}
	

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	@Override
	public void syncData()throws BackofficeManagerException, BackofficeInvalidSessionManagerException,
			BackofficeDBConnectionException, BackofficeWebServicesException {
		try {
			syncDataDao.updateLastTry(AndroidConfigurationParameterName.SYNC_OFFSET_IN_MINUTES.getName());
			
			DLog.i("Starting synchronization process.");
			
			UserAndroid userAndroid = userDao.lastLogin();
			HashMap<Long, UserWSEntity> parseUser = parseUser(userAndroid);
			boolean isUserPersisted = userWSDAO.insert(parseUser.values());
			
			if (isUserPersisted) {
			
				List<PositionAndroid> positionsToSync = positionDao.retrievePositionsToSync();
				DLog.i("Number of positions to sync: "+positionsToSync.size());
				HashMap<Long, PositionWSEntity> parsePositions = parsePositions(positionsToSync);
				if(!parsePositions.isEmpty()) {
					boolean isPersisted = positionWSDAO.insert(parsePositions.values());
					if(isPersisted) {
						positionDao.markAsSynchronized(positionsToSync);
						DLog.i("Position data was successfully synchronized.");
					} else {
						DLog.i("Position data was not synchronized.");
					}
				} else {
					DLog.i("No position found to sync.");
				}
				
			}	
			syncDataDao.updateLastSuccess(AndroidConfigurationParameterName.SYNC_OFFSET_IN_MINUTES.getName());
			
			DLog.i("Ending synchronization process.");
				
		} catch	(BackofficeInvalidSessionDaoException e) {
			DLog.e(e);
			throw new BackofficeInvalidSessionManagerException("Invalid Session.", e);
			
		} catch (BackofficeDaoException e) {
			DLog.e(e);
			throw new BackofficeManagerException("Error while doing data synchronization.", e);
		} 
	}


	@Override
	public void syncParameters() throws BackofficeWebServicesException,
			BackofficeInvalidURLWebServicesException,
			BackofficeConnectionWebServicesException,
			BackofficeDBConnectionException, BackofficeManagerException {
		
		try {
			List<ParameterAndroid> parametersOnline = parameterWSDAO.retrieveParametersOnline(AndroidConfigurationParameterName.getAllParameterNames());
			parameterDao.updateParameters(parametersOnline);
			
			DLog.i("Parameter data was successfully synchronized.");
			
		} catch (BackofficeDaoException e) {
			DLog.e(e);
			throw new BackofficeManagerException("Error while updating configuration parameters", e);
		}
	}
	
	@Override
	public void syncRanking() throws BackofficeWebServicesException,
			BackofficeInvalidURLWebServicesException,
			BackofficeConnectionWebServicesException,
			BackofficeDBConnectionException, BackofficeManagerException {
		
		try {
			List<RankingAndroid> rankings = rankingWSDAO.retrieveRanking();
			rankingDao.deleteAllLines();
			for (RankingAndroid rankingAndroid : rankings) {
				rankingDao.insert(rankingAndroid);
			}
			
			
			DLog.i("Ranking data was successfully synchronized.");
			
		} catch (BackofficeDaoException e) {
			DLog.e(e);
			throw new BackofficeManagerException("Error while updating configuration ranking", e);
		}
	}	
	
	@Override
	public boolean isTimeToSyncData() throws BackofficeManagerException, BackofficeDBConnectionException {
		boolean isTimeToSyncData = false;
		try {
			ParameterAndroid offset = parameterDao.getParameter(AndroidConfigurationParameterName.SYNC_OFFSET_IN_MINUTES.getName());
			if(offset != null && offset.getValue() != null) {
				int offsetInMinutes = Integer.parseInt(offset.getValue());
				
				SyncDataAndroid syncData = syncDataDao.getSyncData(AndroidConfigurationParameterName.SYNC_OFFSET_IN_MINUTES.getName());
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(new Date(syncData.getLastTryDateTime()));
				calendar.add(Calendar.MINUTE, offsetInMinutes);
				
				Calendar now = Calendar.getInstance();
				
				isTimeToSyncData = now.after(calendar);
			}
		} catch (NumberFormatException e) {
			DLog.e(e);
			DLog.e("Parameter "+AndroidConfigurationParameterName.SYNC_OFFSET_IN_MINUTES.getName()+" is not a number.", e);
			
		} catch (BackofficeDaoException e) {
			DLog.e(e);
			throw new BackofficeManagerException(e);
		}
		
		return isTimeToSyncData;
	}
	private HashMap<Long, UserWSEntity> parseUser(UserAndroid userAndroid) {
		HashMap<Long, UserWSEntity> userWSEntityMap = new HashMap<Long, UserWSEntity>();
		
		UserWSEntity userWSEntity = new UserWSEntity();
		userWSEntity.setBrand(userAndroid.getBrand());
		userWSEntity.setImei(userAndroid.getImei());
		userWSEntity.setLastLogin(userAndroid.getLastLogin());
		userWSEntity.setModel(userAndroid.getModel());
		userWSEntity.setName(userAndroid.getName());
		
		userWSEntityMap.put(0l, userWSEntity);
		return userWSEntityMap;
	}	

	private HashMap<Long, PositionWSEntity> parsePositions(List<PositionAndroid> checkInOutpositionsToSync) {
		HashMap<Long, PositionWSEntity> potisionWSEntityMap = new HashMap<Long, PositionWSEntity>(checkInOutpositionsToSync.size());
		for(PositionAndroid pos : checkInOutpositionsToSync) {
			potisionWSEntityMap.put(pos.getXidPosition(), parsePosition(pos));
		}
		return potisionWSEntityMap;
	}
	
	
	private PositionWSEntity parsePosition(PositionAndroid positionAndroid) {
		
		PositionWSEntity positionWSEntity = new PositionWSEntity();
		positionWSEntity.setNuAccuracy(positionAndroid.getAccuracy());
		positionWSEntity.setDtInserted(new Date().getTime());
		positionWSEntity.setDtPosition(positionAndroid.getDateCreated());
		positionWSEntity.setNuLatitude(positionAndroid.getLatitude());
		positionWSEntity.setNuImei(Long.valueOf(positionAndroid.getImei()));
		positionWSEntity.setNuLongitude(positionAndroid.getLongitude());
		positionWSEntity.setDsProvider(positionAndroid.getProvider());
		positionWSEntity.setNuSpeed(positionAndroid.getSpeed());
		
		return positionWSEntity;
	}
}
